package core.util;

import java.util.Collection;
import java.util.Iterator;

public class CollectionUtil {

	public static boolean isEmpty(Collection<?> collection) {
		return (collection == null || collection.isEmpty());
	}

	public static boolean isNotEmpty(Collection<?> collection) {
		return (collection != null && !collection.isEmpty());
	}

	public static <O, I> Collection<O> convert(Collection<I> collection, Convertor<I, O> convertor) {
		if (isEmpty(collection) || convertor == null) {
			return null;
		}

		Collection<O> newCollection = newCollection(collection);
		if (newCollection != null) {
			for (Iterator<I> i = collection.iterator(); i.hasNext();) {
				newCollection.add(convertor.convert(i.next()));
			}
		}

		return newCollection;
	}

	@SuppressWarnings("unchecked")
	public static <T extends Collection<?>> T newCollection(Object reference) {
		Class<Collection<?>> clazz = null;
		if (reference instanceof Collection<?>) {
			clazz = (Class<Collection<?>>) reference.getClass();
			
		} else if (reference instanceof Class<?> && Collection.class.isAssignableFrom((Class<?>) reference)) {
			clazz = (Class<Collection<?>>) reference;
		}
		
		if (clazz != null) {
			try {
				return (T) clazz.newInstance();
			} catch (Exception e) {
			}
		}

		return null;
	}

	@SuppressWarnings("unchecked")
	public static <T, R extends Collection<T>> R match(R collection, Matcher<T> matcher) {
		if (matcher == null) {
			return null;
		}

		return matchAll(collection, matcher);
	}

	@SuppressWarnings("unchecked")
	public static <T, R extends Collection<T>> R match(R collection, Class<? extends R> returnType, Matcher<T> matcher) {
		if (matcher == null) {
			return null;
		}

		return matchAll(collection, returnType, matcher);
	}

	public static <T, R extends Collection<T>> R matchAny(R collection, Matcher<T>... matchers) {
		return match(collection, null, matchers, false);
	}

	public static <T, R extends Collection<T>> R matchAny(R collection, Class<? extends R> returnType,
			Matcher<T>... matchers) {
		return match(collection, returnType, matchers, false);
	}

	public static <T, R extends Collection<T>> R matchAll(R collection, Matcher<T>... matchers) {
		return match(collection, null, matchers, true);
	}

	public static <T, R extends Collection<T>> R matchAll(R collection, Class<? extends R> returnType,
			Matcher<T>... matchers) {
		return match(collection, returnType, matchers, true);
	}

	@SuppressWarnings("unchecked")
	private static <T, R extends Collection<T>> R match(R collection, Class<? extends R> returnType,
			Matcher<T>[] matchers, boolean isMatchAll) {
		if (isEmpty(collection) || ArrayUtil.isEmpty(matchers)) {
			return null;
		}
		
		R matched;
		if (returnType != null) {
			matched = (R) newCollection(returnType);
		} else {
			matched = (R) newCollection(collection);
		}

		if (matched == null) {
			return null;
		}
		
		for (T obj : collection) {
			if (MatchHelper.match(obj, matchers, isMatchAll)) {
				matched.add(obj);
			}
		}

		return matched;
	}
	
	private CollectionUtil() {
	}
}
